package com.clp.inflxudb.core.domain;

import com.clp.inflxudb.core.enums.CompareOp;
import com.clp.inflxudb.core.enums.FluxKVType;
import com.clp.inflxudb.core.enums.LogicOp;
import lombok.Getter;

/**
 * 键值对组（二叉树结构）
 *  单个键值对视为一个键值对组
 *  两个键值对组可以合并为一个更大的键值对组（通过逻辑操作符合并）
 */
@Getter
public class FluxKVGroup {
    private final FluxKV fluxKV;

    private FluxKVGroup leftGroup;
    private FluxKVGroup rightGroup;
    private LogicOp logicOp;

    /**
     * 以叶子结点构造
     * @param fluxKV
     */
    public FluxKVGroup(FluxKV fluxKV) {
        this.fluxKV = fluxKV;
        this.leftGroup = null;
        this.rightGroup = null;
        this.logicOp = null;
    }

    /**
     * 以叶子结点构造
     * @param key
     * @param value
     * @param compareOp
     */
    public FluxKVGroup(String key, Object value, CompareOp compareOp, FluxKVType fluxKVType) {
        this(new FluxKV(key, value, compareOp, fluxKVType));
    }

    /**
     * 以非叶子结点构造
     * @param leftGroup
     * @param rightGroup
     * @param logicOp
     */
    public FluxKVGroup(FluxKVGroup leftGroup, FluxKVGroup rightGroup, LogicOp logicOp) {
        this.fluxKV = null;
        this.leftGroup = leftGroup;
        this.rightGroup = rightGroup;
        this.logicOp = logicOp;
    }

    /**
     * 通过 与 操作和另一个键值对组连接，返回这个连接后的键值对组
     * @param fluxKVGroup
     * @return
     */
    public FluxKVGroup connAnd(FluxKVGroup fluxKVGroup) {
        if (fluxKVGroup == null) return this;
        return conn(fluxKVGroup, LogicOp.and);
    }

    public FluxKVGroup connAnd(String key, Object value, CompareOp compareOp, FluxKVType fluxKVType) {
        return connAnd(new FluxKVGroup(key, value, compareOp, fluxKVType));
    }

    public FluxKVGroup connOr(FluxKVGroup fluxKVGroup) {
        return conn(fluxKVGroup, LogicOp.or);
    }

    public FluxKVGroup connOr(String key, Object value, CompareOp compareOp, FluxKVType fluxKVType) {
        return connOr(new FluxKVGroup(key, value, compareOp, fluxKVType));
    }

    public FluxKVGroup conn(FluxKVGroup fluxKVGroup, LogicOp logicOp) {
        return new FluxKVGroup(this, fluxKVGroup, logicOp);
    }

    public void setLeftGroup(FluxKVGroup fluxKVGroup) {
        this.leftGroup = fluxKVGroup;
    }

    public void setRightGroup(FluxKVGroup fluxKVGroup) {
        this.rightGroup = fluxKVGroup;
    }

    public boolean hasLeftGroup() {
        return leftGroup != null;
    }

    public boolean hasRightGroup() {
        return rightGroup != null;
    }

    public boolean isLeaf() {
        return !hasLeftGroup() && !hasRightGroup();
    }
}
